
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>
    
  JavaScript Arguments - beace lee的博客
  

  </title>
  <meta name="author" content="">
  <meta name="description" content="周日被我射熄火了，现在是周一">

  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <link href="asset/css/screen.css" media="screen, projection" rel="stylesheet" type="text/css">  
  <link href="atom.xml" rel="alternate" title="beace lee的博客" type="application/atom+xml">
  <script src="asset/js/modernizr-2.0.js"></script>
  <script src="asset/js/jquery.min.js"></script>
  <script src="asset/highlightjs/highlight.pack.js"></script>
  <link href="asset/highlightjs/styles/monokai_sublime.css" media="screen, projection" rel="stylesheet" type="text/css">
  <script>hljs.initHighlightingOnLoad();</script>

  <style type="text/css">
  .cat-children-p{ padding: 6px 0px;}
  .hljs{background: none;}
  </style>
  <script type="text/javascript">
  var isAddSildbar = true;
  </script>
  <script src="asset/js/octopress.js" type="text/javascript"></script>
</head>
<script type="text/javascript">
//链接新开窗口
function addBlankTargetForLinks () {
  $('a[href^="http"]').each(function(){
      $(this).attr('target', '_blank');
  });
}
$(document).ready(function(event) {
  addBlankTargetForLinks();
});
</script>
<body   >
  <header role="banner"><hgroup>
  <a href="index.html" class="beace-img">
    <img src="https://images-manager.oss-cn-shanghai.aliyuncs.com/self/logo.jpg" />
  </a>
  <div class="header-title">
    <h1><a href="index.html">beace lee的博客</a></h1>
    <h2>周日被我射熄火了，现在是周一
  </div>
    
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<!-- <form action="https://google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="q" value="site:beace.github.io" />
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form> -->
<a class="beace-github" href="https://github.com/BeAce"></a>
  
<ul class="main-navigation">

  <li id=""><a target="_self" href="index.html">Home</a></li>

  <li id=""><a target="_self" href="archives.html">Archives</a></li>

  <li id=""><a target="_self" href="about.html">About</a></li>

</ul>

</nav>
  <div id="main">
    <div id="content"> 
<div>
	<article class="hentry" role="article">
	<header>
			  	<h1 class="entry-title">JavaScript Arguments</h1>
				<p class="meta"><time datetime="2017-03-24T17:26:49+08:00" pubdate data-updated="true">2017/3/24 17:26 下午</time></p>
			 </header>
		  	<div class="entry-content">
			  	<p>上一次说到了JavaScript中加引号和不加引号的区别，已经认知到了在大体上还是没有区别的。这里我将深入的了解JavaScript函数中的arguments对象，将其运用到实战。</p>

<span id="more"></span><!-- more -->

<h2 id="toc_0">目录</h2>

<ul>
<li>
<a href="#toc_0">目录</a>
</li>
<li>
<a href="#toc_1">正文</a>
</li>
<li>
<a href="#toc_2">Arguments</a>
<ul>
<li>
<a href="#toc_3">arguments中的参数</a>
<ul>
<li>
<a href="#toc_4">特点</a>
</li>
</ul>
</li>
<li>
<a href="#toc_5">arguments中的arguments.callee属性</a>
</li>
<li>
<a href="#toc_6">arguments个数</a>
</li>
<li>
<a href="#toc_7">arguments@@iterator</a>
</li>
</ul>
</li>
<li>
<a href="#toc_8">arguments(object) to array</a>
</li>
</ul>


<h2 id="toc_1">正文</h2>

<p>首先，回顾一下上一次的代码。</p>

<pre><code class="language-js">function getArgs(a, b) {
  console.log(arguments[0])
  console.log(arguments[1])
  console.log(arguments[&#39;0&#39;])
  console.log(arguments[&#39;1&#39;])
}

getArgs(1, 2);

var b = {&quot;b&quot;: &quot;b&quot;};
var b2 = {b: &quot;b&quot;};
console.log(b.b);
console.log(JSON.stringify(b))
console.log(JSON.stringify(b2))
</code></pre>

<p>在这里，我们可以看到其实访问都没有错误。都会返回我们想要的结果。唯一的区别是有引号和没有引号的区别。我们知道JavaScript中表示字符串的时候双引号和单引号是没有区别的（字符串拼接除外），编译器都可以识别。例如上述代码运行时不会出错的。</p>

<p>但是，如果我们想获取getArgs()中参数的个数，可以写成这样吗？</p>

<pre><code class="language-js">function getArgs(a, b) {
  console.log(arguments.length)
}
</code></pre>

<p>答案是肯定的。但arguments仍然不是一个数组，它是一个只具备length属性的对象。</p>

<pre><code class="language-js">function getArgs(a, b) {
  console.log(typeof arguments); // object
}
</code></pre>

<p>可以看出，arguments是object类型的，只有array类型才具有length属性。那为何可以像数组那样访问呢？ </p>

<p>在这里，先打住。我们来看下array是如何获取元素的。</p>

<pre><code class="language-js">const arr = [1,2,3,4];
for (let i = 0; i &lt; arr.length; i ++) {
  console.log(a[i]); //1 2 3 4
}
</code></pre>

<p>上述代码迭代了arr数组，并且我们通过Array[index]的方式进行数组元素的获取。试想一下，如果给index加上引号呢？还能如期获取吗？</p>

<pre><code class="language-js">//将 console.log(a[i]) 替换
console.log(a[i.toString()]) //1 2 3 4
</code></pre>

<p>可以看到，数组如约输出。不信你可以尝试<code>a[&#39;0&#39;]</code>的方式去访问，依然可以获得元素。</p>

<p><em>这是为什么呢？</em></p>

<p>首先，我们来查看下Array在JavaScript中定义的类型。</p>

<pre><code class="language-js">typeof Array //object
</code></pre>

<p>可以看到，Array是object类型。尽管我们没有必要这样加引号的去访问，但是事实上是可以这样的。因为a[0]中的整型0被JavaScript强制地隐式转换（toString()）为字符串&#39;0&#39;。如果你不相信，Mozilla MDN上有一个非常好的例子来说明这一点 （<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array%EF%BC%89">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array）</a> 。比如：</p>

<p>我们声明一个数组，并且像如下访问。</p>

<pre><code class="language-js">var arr = [1,2,3,4,5];
console.log(arr[01] === arr[1]); // true
//这里 arr[&#39;01&#39;] === undefined
console.log(arr[&#39;01&#39;] === arr[&#39;1&#39;]) // false
</code></pre>

<p>我们知道，在整数的高位补0，十进制里还等于其本身。</p>

<pre><code class="language-js">01 === 1 // true
</code></pre>

<p>而数字作为字符串比较，当然就不同。</p>

<pre><code class="language-js">&#39;01&#39; === &#39;1&#39; //false
</code></pre>

<blockquote>
<p>The 2 in years[2] is coerced into a string by the JavaScript engine through an implicit toString conversion. It is for this reason that &#39;2&#39; and &#39;02&#39; would refer to two different slots on the years object and the following example could be true. —— <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">by Mozilla MDN JavaScript Array</a></p>
</blockquote>

<p>这下你应当知道，原来JavaScript也是通过”强制补引号“的方式进行数组索引的处理。那就不难理解为何arguments也可以这样了。容易进入误区的是arguments[0]这样的访问方式容易让人觉得他就是个数组。对于引号没有研究透彻的JavaScript开发者来说，是很大一个误区。</p>

<h2 id="toc_2">Arguments</h2>

<p>现在正式进入arguments的正题。话说既然arguments是个对象，那它里面有什么呢？</p>

<p><img src="media/14903476099970/14903511503835.jpg" alt=""/></p>

<p>这里打印了showMeArgs(1, 2)中的arguments对象。有如下属性</p>

<table>
<thead>
<tr>
<th>属性</th>
<th>值</th>
<th>含义</th>
</tr>
</thead>

<tbody>
<tr>
<td>0</td>
<td>1</td>
<td>function中的第一个参数</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>function中的第二个参数</td>
</tr>
<tr>
<td>callee</td>
<td>showMeArgs(a, b)</td>
<td>当前执行的函数</td>
</tr>
<tr>
<td>length</td>
<td>2</td>
<td>内置属性，获取参数个数</td>
</tr>
<tr>
<td>iterator</td>
<td>array</td>
<td>返回一个新的Array Iterator对象，该对象包含参数中每个索引的值</td>
</tr>
</tbody>
</table>

<h3 id="toc_3">arguments中的参数</h3>

<p>上面图表中的<code>0,1</code>，即对应形参的<code>a,b</code>。</p>

<h4 id="toc_4">特点</h4>

<ul>
<li>可以通过arguments[0]的方式获取或设置属性，设置属性时，会覆盖实参</li>
</ul>

<pre><code class="language-js">function showMeArgs(a, b) {
  arguments[0] = 10;
  console.log(arguments[0]); //10
  console.log(a + b);
}

showMeArgs(1, 2); //12
</code></pre>

<ul>
<li>当默认参数提供时，实参不会被覆盖</li>
</ul>

<pre><code class="language-js">function showMeArgs(a = 1, b) {
  arguments[0] = 100;
  console.log(a + b);
}
showMeArgs(10, 3) // 13
</code></pre>

<ul>
<li>ES6 当使用省略参数（rest parameters）的写法时，arugments也可以返回</li>
</ul>

<pre><code class="language-js">function showMeArgs(...args) {
  console.log(arguments);
}
showMeArgs(1, 2, 3); // object
</code></pre>

<h3 id="toc_5">arguments中的arguments.callee属性</h3>

<p>包含当前执行的功能。这句话可能有些别扭。通俗一点来说，它可以指代该函数函数体内当前执行的函数。</p>

<p>语言描述可能不太准确，在这里可以看一个例子。</p>

<p>如果有一个数组，这个数组我希望能够求出每个元素从<em>0加到该元素的和</em>并返回。可以这样来实现。</p>

<ul>
<li>先把求和这个动作抽象出来。</li>
</ul>

<pre><code class="language-js">function plus(n) {
  return n === 0 ? 0 : plus(n - 1) + n;
}
</code></pre>

<ul>
<li>接着迭代数组加求和</li>
</ul>

<pre><code class="language-js">[0,1,2,3,4,5,6].map(n =&gt; plus(n)) //[0, 1, 3, 6, 10, 15, 21]
</code></pre>

<p>可以看到，我们通过调用plus()实现了。如果我们觉得业务逻辑比较简单，为了代码简洁，想要把抽象出来的东西放在map方法中。</p>

<pre><code class="language-js">[0,1,2,3,4,5,6].map(n =&gt; n === 0 ? 0 : (n - 1) + n); // [0, 1, 3, 5, 7, 9, 11]
</code></pre>

<p>可以看到并没有按照想要的结果去求和，反而直接计算了。这时我们可以使用callee方法代表一个匿名函数来解决这一问题。</p>

<pre><code class="language-js">[0,1,2,3,4,5,6].map(function(n){
  return n === 0 ? 0 : arguments.callee(n - 1) + n
});
</code></pre>

<p>这个时候，我们就不能够使用ES6箭头函数的新特性了。因为arguments为undefined。</p>

<pre><code class="language-sh">Uncaught ReferenceError: arguments is not defined
</code></pre>

<p>相比之下，其实这种递归调动以及内联函数的写法很不友好。我们无法抽象出想要的方法，并且无法进行进一步的优化。在高阶函数中，经常很多函数作为另一个函数的参数进行传递，这样的写法难以维护。如果大量使用，甚至可能造成性能上的问题，例如不可避免的嵌套的匿名回调函数（callback function）等。将来的可能被废弃掉。</p>

<h3 id="toc_6">arguments个数</h3>

<p>通过arguments.length可以获取函数中参数的个数。<strong>但其不是数组</strong></p>

<pre><code class="language-js">function getArgs(a, b) {
  console.log(arguments.length) //2
}
</code></pre>

<h3 id="toc_7">arguments<a href="">@@iterator</a></h3>

<p>Array的迭代器。类似Array.prototype.value的使用，现在除Firefox Nightly版本能够体验外，各大浏览器均不支持。例如：</p>

<pre><code class="language-js">var arr = [&#39;w&#39;, &#39;y&#39;, &#39;k&#39;, &#39;o&#39;, &#39;p&#39;];
var iterator = arr.values();
for (let letter of iterator) {
  console.log(letter);
}
</code></pre>

<h2 id="toc_8">arguments(object) to array</h2>

<p>通过上面的所有表述，我们已经知道arguments已经是一个object类型。那可以通过一定方式将arguments的类型转换为array吗？</p>

<p>可能似乎没有这样的需求。我来介绍一个例子。</p>

<blockquote>
<p>以下灵感来自 <a href="https://t.75team.com/video/">https://t.75team.com/video/</a> JavaScript视频</p>
</blockquote>

<p>比如，你的一个同事或者合作的伙伴写了一个改变元素颜色的函数，如下。</p>

<pre><code class="language-js">function setColor(color, ele) {
  ele.style.color = color;
}
</code></pre>

<p>这个函数看起来没有什么特别，唯一让人看起来别扭的可能是参数的位置。我们可能习惯第一个形参为元素（ele），第二个形参为颜色（color），因此我们可以实现一个方法将参数内容转置， 这里就用到了arguments。</p>

<pre><code class="language-js">function setColorReverse(fn) {
  return function(color, ele) {
    var args = Array.prototype.slice.call(arguments);
    fn.apply(this, args.reverse());
  }
}
setColorReverse(setColor(&#39;container&#39;, &#39;blue&#39;));
</code></pre>

<p>同样，除了像Array.prototype.slice.call(arguments)这样的处理之外，还可以替换为：</p>

<pre><code class="language-js">[].slice.call(arguments) || Array.from(arguments)
</code></pre>

<p>在ES6中，这样写更简单。</p>

<pre><code class="language-js">function reverseArgs(fn) {
  return function(...args) {
    fn.apply(null, [...args].reverse());
  }
}

reverseArgs(setColor)(content, &#39;blue&#39;);  // so the color of content is blue
</code></pre>

			</div>

		
	  
		<footer>
		 <p class="meta">

			<strong>Categories:</strong>&nbsp; 
			<span class="categories">
			
			    <a class='category' href='javascript-funny.html'>javascript-funny</a>&nbsp;
			 
			</span>
		    </p>
		    <p class="meta">
		      
		 </p>
	    
		<div class="sharing">
		  <!-- 多说公共JS代码 start (一个网页只需插入一次) -->
<script type="text/javascript">
var duoshuoQuery = {short_name:"shimin"};
  (function() {
    var ds = document.createElement('script');
    ds.type = 'text/javascript';ds.async = true;
    ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
    ds.charset = 'UTF-8';
    (document.getElementsByTagName('head')[0] 
     || document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
  </script>
<!-- 多说公共JS代码 end -->
          

          
              <div class="ds-thread" data-thread-key="JavaScript-arguments.html" data-url="beace.github.io/JavaScript-arguments.html" data-title="JavaScript Arguments"></div>
          

		</div>

	    <p class="meta">
	    
	        <a class="basic-alignment left" href="14921760383479.html" 
	        title="Previous Post: 【摘抄】You Don't Need jQuery (选自 https://travis-ci.org/oneuijs/You-Dont-Need-jQuery)">&laquo; 【摘抄】You Don't Need jQuery (选自 https://travis-ci.org/oneuijs/You-Dont-Need-jQuery)</a>
	    
	    
	        <a class="basic-alignment right" href="javascript-object-funny.html" 
	        title="Next Post: JavaScript一些有趣的地方">JavaScript一些有趣的地方 &raquo;</a>
	    
	    </p>
	  </footer>
	</article>
</div>
 <aside class="sidebar"> 

	<section>
	  <h1>Categories</h1>
	  <ul id="recent_posts">
	  
	      <li class="post">
	        <a href="doc-css.html"><strong>doc-css&nbsp;(5)</strong></a>
	        
	        
	        
	      </li>
	  
	      <li class="post">
	        <a href="json-server.html"><strong>json-server&nbsp;(1)</strong></a>
	        
	        
	        
	      </li>
	  
	      <li class="post">
	        <a href="javascript-funny.html"><strong>javascript-funny&nbsp;(2)</strong></a>
	        
	        
	        
	      </li>
	  
	      <li class="post">
	        <a href="star.html"><strong>star&nbsp;(1)</strong></a>
	        
	        
	        
	      </li>
	  
	      <li class="post">
	        <a href="html5.html"><strong>html5&nbsp;(1)</strong></a>
	        
	        
	        
	      </li>
	   
	  </ul>
	</section>
	<section>
	  <h1>Recent Posts</h1>
	  <ul id="recent_posts">
	  
	      
		      <li class="post">
		        <a href="HTML5%20dataset.html">HTML5 dataset 属性不为人知的地方（命名规则和原理）</a>
		      </li>
	     
	  
	      
		      <li class="post">
		        <a href="14921760383479.html">【摘抄】You Don't Need jQuery (选自 https://travis-ci.org/oneuijs/You-Dont-Need-jQuery)</a>
		      </li>
	     
	  
	      
		      <li class="post">
		        <a href="JavaScript-arguments.html">JavaScript Arguments</a>
		      </li>
	     
	  
	      
		      <li class="post">
		        <a href="javascript-object-funny.html">JavaScript一些有趣的地方</a>
		      </li>
	     
	  
	      
		      <li class="post">
		        <a href="css-draw-rectangle.html">分享一些CSS画图技巧(1)——矩形</a>
		      </li>
	     
	  
	      
	  
	      
	  
	      
	  
	      
	  
	      
	   
	  </ul>
	</section>
	
</aside> </div></div>
  <footer role="contentinfo"><p>
  Copyright &copy; 2017 -  -
  <span class="credit">Powered by <a target="_blank" href="https://beace.github.io">Beace</a> &nbsp;&nbsp; Theme by <a href="http://octopress.org">Octopress</a></span>
</p>

</footer>
<script src="asset/js/big-picture.min.js"></script>  
<script>
  (function() {
    function setClickHandler(id, fn) {
      document.querySelector(id).onclick = fn;
    }
    setClickHandler('body', function(e) {
      e.target.tagName === 'IMG' && BigPicture({
        el: e.target,
        imgSrc: e.target.src
      });
    });
  })()
</script>

  


<script type="text/javascript">
var duoshuoQuery = {short_name:'shimin'};
  (function() {
    var ds = document.createElement('script');
    ds.type = 'text/javascript';ds.async = true;
    ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
    ds.charset = 'UTF-8';
    (document.getElementsByTagName('head')[0] 
     || document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
  </script>
    



<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-83986231-2', 'auto');
  ga('send', 'pageview');

</script>
</body>
</html>